package com.dyh.quickdemozwei;

import javassist.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class TestScLog {


//    class C{
//        Boolean isXXX;
//
//        public Boolean getXXX() {
//            return isXXX;
//        }
//
//        public void setXXX(Boolean XXX) {
//            isXXX = XXX;
//        }
//    }

    static final String hello = "hello";
    static {
        ClassPool pool = ClassPool.getDefault();
        pool.appendClassPath(new ClassClassPath(TestScLog.class));

        PathMatchingResourcePatternResolver resolver=new PathMatchingResourcePatternResolver();
        CachingMetadataReaderFactory factory=new CachingMetadataReaderFactory();
        try {
            //com/taobao/top/schema/**/*.clas

            /*
            ch.qos.logback.classic.Logger

            ch.qos.logback.classic 包名 .改/ +  ""

            */
            //  /**/*.class

            Resource[] resources=resolver.getResources("ch/qos/logback/classic/**/*.class");


            List<CtClass> ctClasses=new ArrayList<>();
            for(Resource resource : resources){
                MetadataReader reader=factory.getMetadataReader(resource);
                ClassMetadata metadata=reader.getClassMetadata();

//                log.info("{} {}",metadata.getClassName(),metadata.getSuperClassName());


                /*ch.qos.logback.classic.Logger java.lang.Object*/


                /*
                ctClass.getMethod("error","(Lorg/slf4j/Marker;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V")
                */

                if (metadata.getClassName().endsWith(".Logger"))
               {
                    CtClass ctClass=pool.getCtClass(metadata.getClassName());
//                    System.out.println("class:"+metadata.getClassName());

//                    CtMethod ctMethod = ctClass.getMethod("error","(Ljava/lang/String;[Ljava/lang/Object;)V");
//
//                     ctMethod.insertAfter("System.out.println(\"我在最后插入了\");");

                    for (CtMethod method : ctClass.getMethods()) {

                        if (method.getName().startsWith("error")){
                            method.insertBefore("System.out.println(\"我在最后插入了\");");
                        }
                    }


////                    metadata.get
//                    for (CtMethod method : ctClass.getMethods()) {
//
//                        System.out.println(method.getName()+"--"+ method.getMethodInfo2().getDescriptor());
//
//                    }

                }



//                CtMethod m1 = ctClass.getMethod("log",);
//
//                m1.insertAfter("System.out.println('我在最后插入了');");

//
//                ctMethod.insertAfter("System.out.println("我在最后插入了："+$1);");;

//                CtMethod getValue = new CtMethod(CtClass.intType, "getValue", new CtClass[]{}, ctClass);
//                getValue.setModifiers(Modifier.PUBLIC);
//                getValue.setBody("return 'hello'");
//                ctClass.addMethod(getValue);
//                getValue.setBody("return this.value;");

            }

            for(CtClass ctClass : ctClasses){
                try {
                    ctClass.toClass();
                }catch (Exception e){}
            }

//            System.out.println();
            /*ch.qos.logback.classic.Logger*/

        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    @Test
    public void test(){
        log.error("adwdaw{}","a");
        log.error("adwdaw{} {}","a","b");
//

        try{
            if (1==1)
                throw new RuntimeException("dawd");
        }
        catch (Exception ex){
            log.error("adwdaw{} {}","a","b",ex);

        }


//        log.info("{}",log.getClass().getName());
//        log.info("{}",);
    }


    interface EmptyApi{

    }

     interface HelloApi{
        void hi();
    }

    class C2{
        void c2(){
            System.out.println("c2");
        }
    }

    @Test public void test2() throws Exception {
        ClassPool cp = ClassPool.getDefault();

        cp.appendClassPath(new ClassClassPath(TestIOManger.class));


        CtClass ctClass = cp.getCtClass(C2.class.getName());


        ctClass.addInterface(cp.get(EmptyApi.class.getName()));

        CtMethod ctMethod = ctClass.getMethod("c2","()V");

        ctMethod.insertBefore(" System.out.println(\"before c2\");");



        /*javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of  sun/misc/Launcher$AppClassLoader): attempted  duplicate class definition for name: "com/dyh/quickdemozwei/TestScLog$C2"
         */

//        ctClass.toClass();

//        hs.reload(ApiTest.class.getName(), ctClass.toBytecode());
//        ctClass.toClass();
        /**
         * 这里无法用new的形式来创建一个对象，因为已经classloader中不能有两个相同的对象,否则会报异常如下：
         *Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader):

         **/
        C2 c2 = (C2)ctClass.toClass().newInstance();
        c2.c2();
//        C2 c2 = new C2();
//        c2.c2();




        System.out.println();


    }

    @Test public void test1() throws Exception {
        ClassPool cp = ClassPool.getDefault();

        /*com.a.b.Hello
         * javassist.CannotCompileException: by java.lang.IllegalAccessError: class com.a.b.Hello cannot access its superinterface com.dyh.quickdemozwei.TestScLog$HelloApi

         * */
        String path = "com.dyh.quickdemozwei";

        CtClass ctClass = cp.makeClass(path+".Hello");
//        CtMethod ctMethod = new CtMethod(CtClass.voidType, "hello", new CtClass[]{CtClass.intType, CtClass.doubleType}, ctClass);
        CtMethod ctMethod = new CtMethod(CtClass.voidType, "hi", new CtClass[]{},ctClass);
        //设置hello方法的权限为public
        ctMethod.setBody("System.out.println(\"dawdwad\");");
        ctMethod.setModifiers(Modifier.PUBLIC);

        //向ctClass中添加这个方法
        ctClass.addMethod(ctMethod);

        /*内部类*/
        /*com.dyh.quickdemozwei.TestScLog$HelloApi*/
        System.out.println(HelloApi.class.getName());
        CtClass helloCclass = cp.getCtClass(HelloApi.class.getName());
        ctClass.addInterface(helloCclass);
//        ctClass.setInterfaces(Hello.class);


        CtClass helloClass = cp.getCtClass(path+".Hello");

        HelloApi h = (HelloApi) helloClass.toClass().newInstance();
        h.hi();
    }
}
